#include "RuleHandler.h"
#include "OracleAdapter.h"
#include "MetaXmlHandler.h"
#include "ConnectionString.h"
#include "Comtools.h"
#include <sstream>
#include <comdef.h>

RuleHandler::RuleHandler()
: MetaStorageBase()
{

}

RuleHandler::~RuleHandler()
{

}

void RuleHandler::uploadMetadata(const char* pszXml)
{
  SQLServerAdapter * pAdapt = dynamic_cast<SQLServerAdapter*>(m_pDb);
  if (NULL == pAdapt) return;

  MetaXmlHandler xmlhnd(pszXml);

  HRESULT hr;
  _bstr_t name, xml;

  ADODB::_RecordsetPtr rs;  
  rs.CreateInstance (__uuidof(ADODB::Recordset));  
  hr = rs->Open("METADATA", _variant_t(pAdapt->getConnecion(), false), ADODB::adOpenDynamic, ADODB::adLockOptimistic, ADODB::adCmdTable);  

  xml = xmlhnd.toXml("/event");
  if (_bstr_t("") != xml) { // data is event
    name = xmlhnd.getNodeValue("/event/name");
    
    VARIANT v;
    VariantInit(&v);
    COMTools::PackVariant(&v, _bstr_t(xml), _bstr_t(xml).length());

    rs->AddNew();
    rs->Fields->GetItem(L"name")->Value = _bstr_t(name);
    rs->Fields->GetItem(L"type")->Value = _bstr_t("EVENT");
    rs->Fields->GetItem(L"format")->Value = v;
    rs->Update();
  } else {
    xml = xmlhnd.toXml("/action");
    if (_bstr_t("") != xml) { // data is event
      name = xmlhnd.getNodeValue("/action/name");

      VARIANT v;
      VariantInit(&v);
      COMTools::PackVariant(&v, _bstr_t(xml), _bstr_t(xml).length());

      rs->AddNew();
      rs->Fields->GetItem(L"name")->Value = _bstr_t(name);
      rs->Fields->GetItem(L"type")->Value = _bstr_t("ACTION");
      rs->Fields->GetItem(L"format")->Value = v;
      rs->Update();
    } else {
      ::MessageBox(NULL, "Unknown metadata", "Warning", MB_ICONWARNING | MB_OK);
    }
  }
  try { rs->Close(); } catch (...) {}
}

void RuleHandler::expandActions()
{
  SQLServerAdapter * pAdapt = dynamic_cast<SQLServerAdapter*>(m_pDb);
  if (NULL == pAdapt) return;

  HRESULT hr;

  _bstr_t sql =  " select name, type, format, datalength(format) * 2 as datasize "
                 " from metadata "
                 " where type = 'ACTION' ";
  
  ADODB::_RecordsetPtr rs;  
  hr = rs.CreateInstance (__uuidof(ADODB::Recordset));  
  hr = rs->Open(sql, _variant_t(pAdapt->getConnecion(), false), ADODB::adOpenDynamic, ADODB::adLockOptimistic, ADODB::adCmdText);  
  if (!rs->ADOEOF) hr = rs->MoveFirst();
  while (S_OK == hr && !rs->ADOEOF) {          
    _bstr_t actionname = rs->Fields->GetItem(L"name")->GetValue();
    _bstr_t actiontype = rs->Fields->GetItem(L"type")->GetValue();

    long chunkSize = rs->Fields->GetItem(L"datasize")->GetValue();

    _variant_t val;
    BSTR bdata;
    VariantInit(&val);
    val = rs->Fields->GetItem(L"format")->GetChunk(chunkSize +2);
    COMTools::UnpackVariant(val, &bdata);
    VariantClear(&val);

    _bstr_t vMethodName, vDirection, vExecutable, vMsgID, 
         vSeqName, vSeqNo, vPatternText, vEventName,
         vDescription, vCommand, xml = _bstr_t(bdata);
    long lPatternSize = 0, lSetSize = 0;
        
    std::list<std::string>::iterator ite;
    std::list<std::string> liEventNames;

    MetaXmlHandler xmlhnd(xml);
    vExecutable = xmlhnd.getNodeValue("//executable");
    liEventNames = xmlhnd.getNodeValues("//event/name", liEventNames);
    for (ite = liEventNames.begin(); ite != liEventNames.end(); ++ ite) {
      vEventName = _bstr_t((*ite).c_str());

      {
        _bstr_t sqlDel = " delete from event_action where event_name = '" + _bstr_t(vEventName) + "' and action_name = '" + _bstr_t(actionname) + "' ";
        _bstr_t sqlIns = " insert into event_action (event_name, action_name) "
                         " select '" + _bstr_t(vEventName) + "', '" + _bstr_t(actionname) + "' ";
        try {
          ADODB::_ConnectionPtr c2; 
          hr = c2.CreateInstance(__uuidof(ADODB::Connection), NULL, CLSCTX_INPROC_SERVER);  
          if (S_OK != hr) throw("CreateInstance failed");
          hr = c2->Open(bstr_t(CONNECTSTRING), L"", L"", -1);  
          c2->Execute(sqlDel, NULL, ADODB::adExecuteNoRecords);
          c2->Execute(sqlIns, NULL, ADODB::adExecuteNoRecords);
          c2->CommitTrans();
          c2->Close();
        } catch (...) {
          OutputDebugString("* Store expanded metadata failed");
        }
      }
    }

    std::list<Step*>::iterator ite2;
    std::list<Step*> liSteps;
    xmlhnd.getActionSteps(liSteps);
    for (ite2 = liSteps.begin(); ite2 != liSteps.end(); ++ ite2)
    {
      Step * pStep = (*ite2);
      vSeqNo = pStep->getStepNo();
      vDescription = pStep->getDescription();
      vCommand = pStep->getCommand();

      {
        bstr_t sqlDel = " delete from action where action_name = '" + _bstr_t(actionname) + "' and action_step = '" + _bstr_t(vSeqNo) + "' ";

        bstr_t sqlIns  = " insert into action (action_name, action_step, description, command) "
                         " select '" + _bstr_t(actionname) + "', '" + _bstr_t(vSeqNo) + "', '" + _bstr_t(vDescription) + "', '" + _bstr_t(vCommand) + "' ";
        try {
          ADODB::_ConnectionPtr c2; 
          hr = c2.CreateInstance(__uuidof(ADODB::Connection), NULL, CLSCTX_INPROC_SERVER);  
          if (S_OK != hr) throw("CreateInstance failed");
          hr = c2->Open(bstr_t(CONNECTSTRING), L"", L"", -1);  
          c2->Execute(sqlDel, NULL, ADODB::adExecuteNoRecords);
          c2->Execute(sqlIns, NULL, ADODB::adExecuteNoRecords);
          c2->CommitTrans();
          c2->Close();
        } catch (...) {
          OutputDebugString("* Store expanded metadata failed");
        }
      }
    }
    rs->MoveNext();
  } 
  try { rs->Close(); } catch (...) {}

}

void RuleHandler::expandEvents()
{
  SQLServerAdapter * pAdapt = dynamic_cast<SQLServerAdapter*>(m_pDb);
  if (NULL == pAdapt) return;

  HRESULT hr;
  
  _bstr_t sql =  " select name, type, format, datalength(format) * 2 as datasize "
                 " from metadata "
                 " where type = 'EVENT' ";
  
  ADODB::_RecordsetPtr rs;  
  rs.CreateInstance (__uuidof(ADODB::Recordset));  
  rs->Open(sql, _variant_t(pAdapt->getConnecion(), false), ADODB::adOpenDynamic, ADODB::adLockOptimistic, ADODB::adCmdText);  

  if (!rs->ADOEOF) hr = rs->MoveFirst();
  while (S_OK == hr && !rs->ADOEOF) {          
    _bstr_t eventname = rs->Fields->GetItem(L"name")->GetValue();
    _bstr_t eventtype = rs->Fields->GetItem(L"type")->GetValue();

    long chunkSize = rs->Fields->GetItem(L"datasize")->GetValue();

    _variant_t val;
    BSTR bdata;
    VariantInit(&val);
    val = rs->Fields->GetItem(L"format")->GetChunk(chunkSize +2);
    COMTools::UnpackVariant(val, &bdata);
    VariantClear(&val);

    _bstr_t vMethodName, vDirection, vExecutable, vMsgID, vSeqName, 
         vSeqNo, vPatternMethod, vPatternClass, 
         vSeverity, xml = _bstr_t(bdata);
    long lPatternSize = 0, lSetSize = 0;

    MetaXmlHandler xmlhnd(xml);
    vSeverity = xmlhnd.getAttrValue("//event", "severity");
    vExecutable = xmlhnd.getNodeValue("//executable");
    lSetSize = xmlhnd.getNodeCount("//sequence");
    for (int seq=0; seq<lSetSize; ++seq) {
      _bstr_t expr;
      
      expr = _bstr_t("//sequence["+_bstr_t(seq)+"]/name");
      vSeqName = xmlhnd.getNodeValue(expr);
      expr = _bstr_t("//sequence["+_bstr_t(seq)+"]/name/pattern");
      lPatternSize = xmlhnd.getNodeCount(expr);
      for (int ele=0; ele<lPatternSize; ++ele) {
        expr = _bstr_t("//sequence["+_bstr_t(seq)+"]/name/pattern["+_bstr_t(ele)+"]");
        vSeqNo = xmlhnd.getAttrValue(expr, "sequence");
        expr = _bstr_t("//sequence["+_bstr_t(seq)+"]/name/pattern["+_bstr_t(ele)+"]/method");
        vPatternMethod = xmlhnd.getNodeValue(expr);
        expr = _bstr_t("//sequence["+_bstr_t(seq)+"]/name/pattern["+_bstr_t(ele)+"]/class");
        vPatternClass = xmlhnd.getNodeValue(expr);

        {
          bstr_t sqlDel = "delete from event_pattern where executable = '" + _bstr_t(vExecutable) + "' and event_name = '" + _bstr_t(eventname) + "' ";

          bstr_t sqlIns = " insert into event_pattern (executable, event_name, event_severity, seq_name, seq_number, seq_size, class_name, method_name, direction_type) "
                          " select '" + _bstr_t(vExecutable) + "', '" + _bstr_t(eventname) + "', '"+_bstr_t(vSeverity)+"', '" + _bstr_t(vSeqName) + "', '" + _bstr_t(vSeqNo) + "', '" + _bstr_t(lPatternSize) + "', '"+ _bstr_t(vPatternClass) +"', '" + _bstr_t(vPatternMethod) + "', '" + _bstr_t("entry") + "' ";

          try {
            ADODB::_ConnectionPtr c2; 
            hr = c2.CreateInstance(__uuidof(ADODB::Connection), NULL, CLSCTX_INPROC_SERVER);  
            if (S_OK != hr) throw("CreateInstance failed");
            hr = c2->Open(bstr_t(CONNECTSTRING), L"", L"", -1);  
            if (0 == ele) c2->Execute(sqlDel, NULL, ADODB::adExecuteNoRecords);
            c2->Execute(sqlIns, NULL, ADODB::adExecuteNoRecords);
            c2->CommitTrans();
            c2->Close();
          } catch (...) {
            OutputDebugString("* Store expanded metadata failed");
          }
        }
      }
    }
    rs->MoveNext();
  } 
  hr = rs->Close();
}